﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using University.Workshop.DataAccess;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Resources;
using System.Reflection;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "TraceManager.Publish(System.String,TraceMessageTypes)")]

//[assembly: NeutralResourcesLanguageAttribute("en-US")]

namespace University.Workshop.Model
{
    public class Client : IDisposable
    {

        public string Parameter { get; set; }
       TcpClient client = new TcpClient();
       public NetworkStream ClientStream { get; set; }
        ASCIIEncoding encoder = new ASCIIEncoding();
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                client.Close();
            }
        }
        public void Dispose()
        {
            Dispose(true);
                GC.SuppressFinalize(this);
        }
        public bool GetGameStatus(User user,string game)
        {

            if (user == null)
                throw new ArgumentNullException("user");
         
            if (game == null)
                throw new ArgumentNullException("game");
            this.Parameter = "16 " + user.Name + " " +game;
            Send(this.Parameter);
            if (Receive() == "00")
                return false;
            return true;
        }
        public void SetGameStatus(User user,string game)
        {

            if (user == null)
                throw new ArgumentNullException("user");
         
            if (game == null)
                throw new ArgumentNullException("game");
            this.Parameter = "17 " + user.Name + " "+game;
            Send(this.Parameter);
            Receive();
            
        }
        public void Connect(int port,string ip)
        {
            try
            {
                IPEndPoint serverendpoint = new IPEndPoint(IPAddress.Parse(ip), port);
                client.Connect(serverendpoint);
            }
            catch (ArgumentOutOfRangeException)
            {

            }
            ClientStream = client.GetStream();
        }
        public Client()
        {
            Connect(3000, "127.0.0.1");
        }
        public Client(int port)
        {
            Connect(port, "127.0.0.1");
        }
        public Client(int port,string ip)
        {
            Connect(port,ip);
        }
        static private Object ByteArrayToUser(byte[] arrBytes)
        {
             MemoryStream memoryStream=null;
            try
            {
                memoryStream= new MemoryStream();

                BinaryFormatter binaryFormatter = new BinaryFormatter();
                memoryStream.Write(arrBytes, 0, arrBytes.Length);
                memoryStream.Seek(0, SeekOrigin.Begin);

                Object userReceived = (Object)binaryFormatter.Deserialize(memoryStream);
                
                return userReceived;
            }
            catch (ArgumentNullException)
            {
                return null;
            }
            catch (ArgumentException)
            {
                return null;
            }
            catch (ObjectDisposedException)
            {
                return null;
            }
            catch (IOException)
            {
                return null;
            }
            catch (SerializationException)
            {
                 return null;
            }
            finally
            {
                memoryStream.Dispose();
            }
            
        }

        public void SendBytes(byte[] message)
        {
            if (message == null)
                throw new ArgumentNullException("message");
            byte[] buffer = message;

            ClientStream.Write(buffer, 0, buffer.Length);
            ClientStream.Flush();
        }
        public void Send(string message)
        {
        
                byte[] buffer = encoder.GetBytes(message);

                ClientStream.Write(buffer, 0, buffer.Length);
                ClientStream.Flush();
            
        }

        public void SendImage(byte[] message)
        {
            if (message == null)
                throw new ArgumentNullException("message");
            byte[] buffer = message;

            ClientStream.Write(buffer, 0, buffer.Length);
            ClientStream.Flush();
        }
        public int SendData(string userName,long chips,int level,long timeHandWon, string playersLimit)
        {
            this.Parameter=("02 " + userName+" "+chips+" "+level+" "+timeHandWon+" "+playersLimit);
            Send(this.Parameter);
           // receive();
            string[] result = Receive().Split(' ');
            if (result[0] == "01")
            {
                return Convert.ToInt32(result[1],CultureInfo.InvariantCulture);
            }
            return 0;

        }
        public string ReceiveUser()
        {
            try
            {
                this.Parameter = ("ok");
                Send(this.Parameter);
                string result = Receive();

                return result;
            }
            catch (ArgumentNullException)
            {
                return null;
            }
            catch (ArgumentOutOfRangeException)
            {
                return null;
            }
            catch (IOException)
            {
                return null;
            }
            catch (ObjectDisposedException)
            {
                return null;
            }
        }

        /*public MemoryStream ReceiveUserMemory(ref string name)
        {
            this.Parameter = ("ok");
            Send(this.Parameter);
            string[] result = Receive().Split(' ');
            Send(this.Parameter);
            name = result[0];
            MemoryStream memory=null;
            try
            {
                memory = new MemoryStream();

                byte[] buffer = new byte[2048];
                int size = 0;
                while ((size = ClientStream.Read(buffer, 0, buffer.Length)) == 2048)
                {
                    memory.Write(buffer, 0, size);
                }
                memory.Write(buffer, 0, size);
            }
            catch (ArgumentNullException)
            {
            }
            finally
            {
                if(memory!=null)
                memory.Dispose();
            }
            return memory;
                        
        }*/
        public string Receive()
        {
                byte[] message = new byte[1024];
                int bytesread = ClientStream.Read(message, 0, message.Length);
                ClientStream.Flush();
                string p = encoder.GetString(message, 0, bytesread);
                return p;
        }
        public byte[] ReceiveBytes(int size)
        {

            byte[] message = new byte[size];
 ClientStream.Read(message, 0, size);
            ClientStream.Flush();
            return message;
        }
        public bool InsertUserLevel(string userName)
        {
            this.Parameter = "27 " + userName;
            Send(this.Parameter);
            string result = Receive();
            if (result == "01") return true;
            else return false;
        }
        public bool RegisterNewUser(string userName, string password, string mail, string question, string answer,int size)
        {
            this.Parameter = "01 " + userName + " " + mail + " " + password + " " + question + " " + answer + " " + size.ToString(CultureInfo.InvariantCulture);
            Send(this.Parameter);
            string result=Receive();
            
                if ( result== "01") return true;

            return false;
        }

        public int NewTransaction(string toUserName, string fromUserName, long amountToSend, long actualAmount)
        {
            this.Parameter = ("30 " + fromUserName + " " + toUserName + " " + amountToSend.ToString(CultureInfo.InvariantCulture) + " " + actualAmount.ToString(CultureInfo.InvariantCulture));
            Send(this.Parameter);
            string result = Receive();
            ClientStream.Flush();
            result = Receive();

            if (result == "00")
            {
                return (0);
            }
            if (result == "02")
            {
                return 2;
            }
            return (1);
        }

        [CLSCompliantAttribute(false)]
        public Collection<Transaction> GetConsultTransactionBoth(string userName)
        {
            Collection<Transaction> ListBoth = new Collection<Transaction>();
            this.Parameter = "31 " + userName;
            Send(this.Parameter);

            int size = Convert.ToInt16(Receive(), CultureInfo.InvariantCulture);
            this.Parameter = "ok";
            Send(this.Parameter);
            byte[] message = ReceiveBytes(size);
            ListBoth = (Collection<Transaction>)ByteArrayToUser(message);
            return ListBoth;
        }

        [CLSCompliantAttribute(false)]
        public Collection<Transaction> GetConsultTransactionReceived(string userName)
        {
            Collection<Transaction> ListBoth = new Collection<Transaction>();
            this.Parameter = "32 " + userName;
            Send(this.Parameter);

            int size = Convert.ToInt16(Receive(), CultureInfo.InvariantCulture);
            this.Parameter = "ok";
            Send(this.Parameter);
            byte[] message = ReceiveBytes(size);
            ListBoth = (Collection<Transaction>)ByteArrayToUser(message);
            return ListBoth;
        }

        [CLSCompliantAttribute(false)]
        public Collection<Transaction> GetConsultTransactionSend(string userName)
        {
            Collection<Transaction> ListBoth = new Collection<Transaction>();
            this.Parameter = "33 " + userName;
            Send(this.Parameter);

            int size = Convert.ToInt16(Receive(), CultureInfo.InvariantCulture);
            this.Parameter = "ok";
            Send(this.Parameter);
            byte[] message = ReceiveBytes(size);
            ListBoth = (Collection<Transaction>)ByteArrayToUser(message);
            return ListBoth;
        }
       
        public string[] GetQuestionAnswer(string userName)
        {
            this.Parameter = ("03 " + userName);
            Send( this.Parameter);
            string all=Receive();
            string[] words;
            words = all.Split();
            return words;
        }
        public bool ChangePassword(string userName,string newPassword)
        {
            this.Parameter = ("04 " + userName + " " + newPassword);
            Send(this.Parameter);
            string value=Receive();
            if (value == "Ok")
            {
                return true;
            }
            else
                return false;
            
        }
        [CLSCompliantAttribute(false)]
        public Collection<User> GetAllUsers

        {
            get
            {
                Collection<User> users = new Collection<User>();
                this.Parameter = "05 ";
                Send(this.Parameter);

                int size = Convert.ToInt16(Receive(), CultureInfo.InvariantCulture);
                this.Parameter = "ok";
                Send(this.Parameter);
                byte[] message = ReceiveBytes(size);
                users = (Collection<User>)ByteArrayToUser(message);
                return users;
            }
        }
        public bool SendRequest(string userName,string userRequest)
        {
            this.Parameter = ("11 " + userName + " " + userRequest);
            Send(this.Parameter);
            string value=Receive();
            if (value=="ok")
                return true;
            else
                return false;
        }
        [CLSCompliantAttribute(false)]
        public Collection<UserContacts> GetUsersContacts(string user)
        {
            this.Parameter = "12 " + user;
            Send(this.Parameter);
            string size = Receive();
            this.Parameter = "ok";
            Send(this.Parameter);
            Byte[] userBytes=ReceiveBytes(Convert.ToInt32(size,CultureInfo.InvariantCulture));
            return ((Collection<UserContacts>)ByteArrayToUser(userBytes));
        }
        public bool ChangeStatus(string userName, string userRequest, string status)
        {
            this.Parameter = ("13 " + userName + " " + userRequest + " " + status);
            Send(this.Parameter);
            if (Receive() == "ok")
                return true;
            else
                return false;
        }
        public Collection<LevelDatabase> GetAllLevels
        {
            get 
            {
                this.Parameter = "27 ";
                Send(this.Parameter);
                string length = Receive();
                this.Parameter = "Ok";
                Send(this.Parameter);
                Byte[] bytes = ReceiveBytes(Convert.ToInt32(length, CultureInfo.InvariantCulture));
                Collection<LevelDatabase> levels = (Collection<LevelDatabase>)ByteArrayToUser(bytes);
                return levels;
            }
        }

        [CLSCompliantAttribute(false)]
        public Collection<User> GetAllHands
        {
            get
            {
                Collection<User> users = new Collection<User>();
                this.Parameter = "47 ";
                Send(this.Parameter);

                int size = Convert.ToInt16(Receive(), CultureInfo.InvariantCulture);
                this.Parameter = "ok";
                Send(this.Parameter);
                byte[] message = ReceiveBytes(size);
                users = (Collection<User>)ByteArrayToUser(message);
                return users;
            }
        }

        public long BestHand(string userName)
        {
            this.Parameter = ("77 " + userName);
            Send(this.Parameter);
            long amount = Convert.ToInt64(Receive(),CultureInfo.InvariantCulture);
            return amount;
        }
    }
}
